/*
 * @(#)ConfigurationBuilder.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.core.config;

import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Node;

import com.nhncorp.lucy.common.config.ConfigurationAware;
import com.nhncorp.lucy.common.util.XMLDOMUtil;
import com.nhncorp.usf.core.util.StringUtil;

/**
 * usf 내에서 초기화할 객체 생성
 * {@link ConfigurationLoaderListener}에 의해 호출된다.
 *
 * @author Web Platform Development Team
 */
public class ConfigurationBuilder implements ConfigurationAware {
    Log log = LogFactory.getLog(ConfigurationBuilder.class);

    /**
     * usf 에서 필요로 하는 객체들을 생성한다.
     * 
     * @param configurationNode the Node
     */
    public void build(Node configurationNode) {
        log.debug(" -- [ConfigurationBuilder/build]");

        buildAttributeConfigs(configurationNode);
        buildInvokerConfigs(configurationNode);
        buildReplaceAllConfigs(configurationNode);
        buildResultTypeConfigs(configurationNode);
        buildInterceptorConfigs(configurationNode);
        buildObjectWatcher(configurationNode);
    }

    /**
     * Dynamic build.
     *
     * @param configurationNode the configuration node
     */
    public void dynamicBuild(Node configurationNode) {
        log.debug(" -- [ConfigurationBuilder/dynamic-build]");

        buildAttributeConfigs(configurationNode);
        buildResultTypeConfigs(configurationNode);
        buildInterceptorConfigs(configurationNode);
        buildObjectWatcher(configurationNode);
    }

    /**
     * Builds the object watcher.
     *
     * @param configurationNode the configuration node
     * @return true, if successful
     */
    @SuppressWarnings("deprecation")
	public boolean buildObjectWatcher(Node configurationNode) {
        Node objectWatcherNode = XMLDOMUtil.getNode(configurationNode, "usf:object-watcher");
        String period = XMLDOMUtil.getValue(objectWatcherNode, "@period");
        String delay = XMLDOMUtil.getValue(objectWatcherNode, "@delay");
        String use = XMLDOMUtil.getValue(objectWatcherNode, "@use");

        ObjectWatcherInfo objectWatcherInfo = ObjectWatcherInfo.getInstance();

        if (StringUtil.isNotEmpty(period, false)) {
            objectWatcherInfo.setPeriod(Long.parseLong(period));
        }

        if (StringUtil.isNotEmpty(delay, false)) {
            objectWatcherInfo.setDelay(Long.parseLong(delay));
        }

        if (StringUtil.isNotEmpty(use, false)) {
            objectWatcherInfo.setUse(Boolean.valueOf(use));
        }

        return true;
    }

    /**
     * {@link AttributeInfo} 로의 정보 빌드.
     * 
     * @param configurationNode the Node
     */
    @SuppressWarnings("deprecation")
    public void buildAttributeConfigs(Node configurationNode) {
        log.debug(" -- [ConfigurationBuilder/buildAttributeConfigs]");

        AttributeInfo attributeInfo = AttributeInfo.getInstance();
        attributeInfo.clear();

        Iterator<Node> attributeIterator = XMLDOMUtil.getNodeIterator(configurationNode, "usf:attributes/usf:attribute");

        while (attributeIterator.hasNext()) {
            Node attributeNode = attributeIterator.next();
            String name = XMLDOMUtil.getValue(attributeNode, "@name");

            // for supporting inheriance
            if (!attributeInfo.containsKey(name)) {
                attributeInfo.addAttribute(name, XMLDOMUtil.getValue(attributeNode, "@value"));
            }
        }
    }

    /**
     * {@link ReplaceAllInfo} 로의 정보 빌드.
     * 
     * @param configurationNode the Node
     */
    @SuppressWarnings("deprecation")
    public void buildReplaceAllConfigs(Node configurationNode) {
        log.debug(" -- [ConfigurationBuilder/buildReplaceAllConfigs]");

        ReplaceAllInfo replaceAllInfo = ReplaceAllInfo.getInstance();
        replaceAllInfo.clear();

        Iterator<Node> replaceAllIterator = XMLDOMUtil.getNodeIterator(configurationNode, "usf:replace-all/usf:replace");

        while (replaceAllIterator.hasNext()) {
            Node replaceAllNode = replaceAllIterator.next();
            String oldValue = XMLDOMUtil.getValue(replaceAllNode, "@oldValue");
            String newValue = XMLDOMUtil.getValue(replaceAllNode, "@newValue");
            replaceAllInfo.putReplaceInfo(oldValue, newValue);
        }
    }

    /**
     * {@link Invoker} 로의 정보 빌드.
     * 
     * @param configurationNode the Node
     */
    @SuppressWarnings("deprecation")
    public void buildInvokerConfigs(Node configurationNode) {
        log.debug(" -- [ConfigurationBuilder/buildInvokerConfigs]");

        ConnectorInfos connectorInfos = ConnectorInfos.getInstance();

        // default-connector
        String defaultConnector = XMLDOMUtil.getValue(configurationNode, "usf:connectors/@default-connector");
        connectorInfos.setDefaultConnector(defaultConnector);

        Iterator<Node> connectorIterator = XMLDOMUtil.getNodeIterator(configurationNode, "usf:connectors/usf:connector");

        while (connectorIterator.hasNext()) {
            Node peerNode = connectorIterator.next();
            ConnectorInfo peerInfo = new ConnectorInfo(XMLDOMUtil.getValue(peerNode, "@id"),
                                                       XMLDOMUtil.getValue(peerNode, "@address"));
            Iterator<Node> propertyIterator = XMLDOMUtil.getNodeIterator(peerNode, "usf:properties/usf:property");

            while (propertyIterator.hasNext()) {
                Node propertyNode = propertyIterator.next();
                peerInfo.addProperty(XMLDOMUtil.getValue(propertyNode, "@name"), XMLDOMUtil.getValue(propertyNode,
                                                                                                     "@value"));
            }

            connectorInfos.putConnectorInfo(peerInfo.getId(), peerInfo);
        }
    }

    /**
     * {@link ResultTypeInfo} 로의 정보 빌드.
     * 
     * @param configurationNode the Node
     */
    @SuppressWarnings("deprecation")
    public void buildResultTypeConfigs(Node configurationNode) {
        log.debug(" -- [ConfigurationBuilder/buildResultTypeConfigs]");

        ResultTypeInfo resultTypeInfo = ResultTypeInfo.getInstance();
        resultTypeInfo.clear();

        Iterator<Node> resultTypeIterator = XMLDOMUtil.getNodeIterator(configurationNode,
                                                                       "usf:result-types/usf:result-type");

        while (resultTypeIterator.hasNext()) {
            Node resultTypeNode = resultTypeIterator.next();
            String name = XMLDOMUtil.getValue(resultTypeNode, "@name");

            if (!resultTypeInfo.containsKey(name)) {
                resultTypeInfo.addResultTypeInfo(name, XMLDOMUtil.getValue(resultTypeNode, "@class"));
            }
        }
    }

    /**
     * {@link InterceptorInfo} 로의 정보 빌드.
     * 
     * @param configurationNode the Node
     */
    @SuppressWarnings("deprecation")
    public void buildInterceptorConfigs(Node configurationNode) {
        log.debug(" -- [ConfigurationBuilder/buildInterceptorConfigs]");

        InterceptorInfo interceptorInfo = InterceptorInfo.getInstance();
        interceptorInfo.clean();

        // default Interceptor Stack
        Node defaultInterceptorStackNode = XMLDOMUtil.getNode(configurationNode,
                                                              "usf:interceptors/usf:default-interceptor-ref");
        interceptorInfo.setDefaultInterceptorRef(XMLDOMUtil.getValue(defaultInterceptorStackNode, "@name"));

        // interceptor
        Iterator<Node> interceptorIterator = XMLDOMUtil.getNodeIterator(configurationNode,
                                                                        "usf:interceptors/usf:interceptor");

        while (interceptorIterator.hasNext()) {
            Node interceptorNode = interceptorIterator.next();
            String name = XMLDOMUtil.getValue(interceptorNode, "@name");

            if (!interceptorInfo.containsInterceptor(name)) {
                String clazz = XMLDOMUtil.getValue(interceptorNode, "@class");
                interceptorInfo.addInterceptorInfo(name, clazz);
                log.debug(" -- [InterceptorConfigs] " + name + ", " + clazz);
            }
        }

        // interceptorStack
        Iterator<Node> interceptorStackIterator = XMLDOMUtil.getNodeIterator(configurationNode,
                                                                             "usf:interceptors/usf:interceptor-stack");

        while (interceptorStackIterator.hasNext()) {
            Node interceptorStackNode = interceptorStackIterator.next();
            String interceptorStackName = XMLDOMUtil.getValue(interceptorStackNode, "@name");

            if (interceptorInfo.containsInterceptorStackInfo(interceptorStackName)) {
                continue;
            }

            InterceptorStackInfo interceptorStackInfo = new InterceptorStackInfo(interceptorStackName);
            Iterator<Node> interceptorRefIterator = XMLDOMUtil.getNodeIterator(configurationNode,
                                                                               "usf:interceptors/usf:interceptor-stack[@name='" + interceptorStackName + "']/usf:interceptor-ref");

            while (interceptorRefIterator.hasNext()) {
                Node interceptorRefNode = interceptorRefIterator.next();
                interceptorStackInfo.addInterceptorRef(XMLDOMUtil.getValue(interceptorRefNode, "@name"));
            }

            interceptorInfo.addInterceptorStackInfo(interceptorStackName, interceptorStackInfo);
        }
    }
}